﻿using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using WT.OpenIddict.Domain.Services;
using WT.OpenIddict.EntityFrameWorkCore;

namespace WT.OpenIddict.Repository.Services;

public class BaseRepository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class where TKey : new()
{
    private readonly OpenIddictDbContext _dbContext;
    private readonly DbSet<TEntity> _dbSet;

    public BaseRepository(OpenIddictDbContext dbContext)
    {
        _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
        _dbSet = _dbContext.Set<TEntity>();
    }

    /// <summary>
    ///     软删除过滤
    /// </summary>
    private Expression<Func<TEntity, bool>> expression => e => !EF.Property<bool>(e, "IsDelete");

    public bool HasSoftDelete => typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity));

    public async Task<IQueryable<TEntity>> GetQueryableAsync(bool isOpenSoftDeleteFilter = true)
    {
        // 注意：这个方法实际上不需要是异步的，因为没有执行数据库查询
        return GetQueryable(isOpenSoftDeleteFilter);
    }

    public async Task<TEntity> InsertAsync(TEntity entity, bool isAutoSave = false)
    {
        var entityInsert = await _dbSet.AddAsync(entity);
        if (isAutoSave) await SaveChangeAsync();
        return entityInsert.Entity;
    }

    public async Task InsertManyAsync(IQueryable<TEntity> entities, bool isAutoSave = false)
    {
        await _dbSet.AddRangeAsync(entities);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task InsertManyAsync(List<TEntity> entities, bool isAutoSave = true)
    {
        await _dbSet.AddRangeAsync(entities);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task<TEntity> UpdateAsync(TEntity entity, bool isAutoSave = false)
    {
        var entityUpdate = _dbSet.Update(entity);
        if (isAutoSave) await SaveChangeAsync();
        return entityUpdate.Entity;
    }

    public async Task UpdateManyAsync(IQueryable<TEntity> entities, bool isAutoSave = false)
    {
        _dbSet.UpdateRange(entities);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task UpdateManyAsync(List<TEntity> entities, bool isAutoSave = true)
    {
        _dbSet.UpdateRange(entities);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task DeleteAsync(TKey id, bool isSoftDelete = true, bool isAutoSave = true)
    {
        var entity = await _dbSet.FindAsync(id);
        if (entity != null)
        {
            await DeleteAsync(entity, isSoftDelete, false); // 不立即保存
            if (isAutoSave) await SaveChangeAsync();
        }
    }

    public async Task DeleteAsync(TEntity entity, bool isSoftDelete = true, bool isAutoSave = true)
    {
        if (isSoftDelete && HasSoftDelete)
        {
            var softProperty = entity.GetType().GetProperty("IsDelete");
            softProperty?.SetValue(entity, true);
        }
        else
        {
            _dbSet.Remove(entity);
        }

        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task DeleteManyAsync(IQueryable<TEntity> deleteEntitys, bool isSoftDelete = true,
        bool isAutoSave = true)
    {
        if (isSoftDelete && HasSoftDelete)
            await _dbSet.Where(it => deleteEntitys.Contains(it))
                .ExecuteUpdateAsync(setters => setters.SetProperty(e => ((ISoftDelete)e).IsDelete, true));
        else
            _dbSet.RemoveRange(deleteEntitys);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task DeleteManyAsync(List<TEntity> deleteEntitys, bool isSoftDelete = true, bool isAutoSave = true)
    {
        if (isSoftDelete && HasSoftDelete)
            await _dbSet.Where(it => deleteEntitys.Contains(it))
                .ExecuteUpdateAsync(setters => setters.SetProperty(e => ((ISoftDelete)e).IsDelete, true));
        else
            _dbSet.RemoveRange(deleteEntitys);
        if (isAutoSave) await SaveChangeAsync();
    }

    public async Task<TEntity> FindAsync(TKey id, bool isOpenSoftDeleteFilter = true)
    {
        if (isOpenSoftDeleteFilter && HasSoftDelete)
            return await _dbSet.FirstOrDefaultAsync(e =>
                ((IEntity<TKey>)e).Id.Equals(id) && !((ISoftDelete)e).IsDelete);

        return await _dbSet.FindAsync(id);
    }

    public async Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> predicate, bool isOpenSoftDeleteFilter = true)
    {
        var query = _dbSet.Where(predicate);
        if (isOpenSoftDeleteFilter && HasSoftDelete) query = query.Where(e => !((ISoftDelete)e).IsDelete);
        return await query.FirstOrDefaultAsync();
    }

    public async Task<bool> AnyAsync(Func<TEntity, bool> predicate, bool isOpenSoftDeleteFilter = true)
    {
        Expression<Func<TEntity, bool>> expressionFilter = e => predicate(e);
        if (isOpenSoftDeleteFilter && HasSoftDelete)
            expressionFilter = CombineExpressions(expressionFilter, expression);

        // 注意: 这里使用了 LINQ to Objects，不是数据库查询
        // 如果需要数据库查询，应该使用 Expression<Func<TEntity, bool>> 参数
        return _dbSet.Any(expressionFilter);
    }

    public DbSet<TEntity> GetDbSet()
    {
        return _dbSet;
    }

    public IQueryable<TEntity> GetQueryable(bool isOpenSoftDeleteFilter = true)
    {
        if (HasSoftDelete && isOpenSoftDeleteFilter) return _dbSet.Where(expression);
        return _dbSet;
    }

    private async Task SaveChangeAsync()
    {
        await _dbContext.SaveChangesAsync();
    }

    // 辅助方法：合并两个表达式 (AND 操作)
    private Expression<Func<T, bool>> CombineExpressions<T>(Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T));
        var body = Expression.AndAlso(
            Expression.Invoke(expr1, parameter),
            Expression.Invoke(expr2, parameter)
        );
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }
}